<html>
  <head>
    <meta charset="utf-8" />
<meta name="description" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>加密相关 | Jiang</title>
<link rel="shortcut icon" href="https://cherrylover.github.io/favicon.ico?v=1601447716515">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<link rel="stylesheet" href="https://cherrylover.github.io/styles/main.css">

<script src="https://cdn.bootcss.com/highlight.js/9.12.0/highlight.min.js"></script>
<script src="https://cdn.bootcss.com/moment.js/2.23.0/moment.min.js"></script>


<script async src="https://www.googletagmanager.com/gtag/js?id=UA-143284233-1"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'UA-143284233-1');
</script>

  </head>
  <body>
    <div class="main">
      <div class="main-content">
        <div class="site-header">
  <a href="https://cherrylover.github.io">
  <img class="avatar" src="https://cherrylover.github.io/images/avatar.png?v=1601447716515" alt="">
  </a>
  <h1 class="site-title">
    Jiang
  </h1>
  <p class="site-description">
    我允许你走进我的世界，但不许你在我的世界里走来走去。
  </p>
  <div class="menu-container">
    
      
        <a href="/" class="menu">
          首页
        </a>
      
    
      
        <a href="/archives" class="menu">
          归档
        </a>
      
    
      
        <a href="/tags" class="menu">
          标签
        </a>
      
    
      
        <a href="https://cherrylover.github.io/post/guan-yu-wo/" class="menu">
          关于
        </a>
      
    
  </div>
  <div class="social-container">
    
      
        <a href="https://github.com/CherryLover" target="_blank">
          <i class="fab fa-github"></i>
        </a>
      
    
      
    
      
        <a href="https://juejin.im/user/576d73cd0a2b58006a09ad87" target="_blank">
          <i class="fab fa-weibo"></i>
        </a>
      
    
      
    
      
    
  </div>
</div>

      
        <div class="post-detail">
          <article class="post">
            <h2 class="post-title">
              加密相关
            </h2>
            <div class="post-info">
              <time class="post-time">
                · 2018-10-07 ·
              </time>
              
                <a href="https://cherrylover.github.io/tag/ari5goDnZ/" class="post-tags">
                  # 基础技能
                </a>
              
            </div>
            
              <div class="post-feature-image" style="background-image: url('https://monster-image-backup.oss-cn-shanghai.aliyuncs.com/picgo/encryption.jpg')">
              </div>
            
            <div class="post-content">
              <p>凡是涉及到加密的时候，就涉及到安全，但是，在实际的开发过程中，涉及到安全部分的又比较少，有些甚至是框架给你做好了，不需要自己考虑。但是我们也还是需要去熟悉一下的。加密涉及到的东西不算难，有点杂，有些乱，每个人都会讲一点，但是真的去说的时候又讲不出个所以然。所以导致很多人对加密有些误解。所以希望这篇文章对你有所帮助。</p>
 <!-- more --> 
<p>先说一下加密的概念吧，因为有些东西确实不是加密，又被大家冠以加密的头衔，久而久之加密与非加密就特别容易混淆了。那加密的概念是什么呢？</p>
<blockquote>
<p>在<a href="https://zh.wikipedia.org/wiki/%E5%AF%86%E7%A0%81%E5%AD%A6">密码学</a>中，<strong>加密</strong>（英语：Encryption）是将<a href="https://zh.wikipedia.org/wiki/%E6%98%8E%E6%96%87">明文</a><a href="https://zh.wikipedia.org/wiki/%E4%BF%A1%E6%81%AF">信息</a>改变为难以读取的<a href="https://zh.wikipedia.org/wiki/%E5%AF%86%E6%96%87">密文</a>内容，使之不可读的过程。只有拥有解密方法的对象，经由解密过程，才能将密文还原为正常可读的内容。——维基百科</p>
</blockquote>
<h2 id="base64">Base64</h2>
<p>首先说一下 Base64 ，网上有人说，Base64 是加密，有人说不是。那他到底是不是呢？想回答这个问题，不难，了解一下 Base64 就行。</p>
<p>Base64 是一种使用 64 个字符来表示二进制数据的一种编码方式。主要作用是将二进制数据重新编码使其成为文本，便于传输。什么意思？举个例子。</p>
<blockquote>
<p>比如需要开发一个上传图片的功能，但是我们没有一个用于独立的上传图片的接口，怎么办呢？网页或客户端将图片使用 Base64 转一下，让它成为字符串数据，然后发送字符串即可。</p>
<p>下表为 Base64 码表，图片来自维基百科。</p>
</blockquote>
<figure data-type="image" tabindex="1"><img src="https://monster-image-backup.oss-cn-shanghai.aliyuncs.com/picgo/base64table.jpg" alt="Base64码表" loading="lazy"></figure>
<p>当然，非二进制数据即文本数据也是可以转换的，但是本来就是文本数据（字符串）你再使用 Base64 转换一下，干啥呢？啥，<strong>安全</strong>？<strong>高效</strong>？</p>
<p>简单来说 Base64 是通过将每 6 位为一个看成一个字节，然后映射到 Base64 的码表中得到相应的字符串。<a href="https://zh.wikipedia.org/wiki/Base64">点击这里查看更多关于Base64的详细信息</a> 因为其转换过程的计算方法是公开的，所以在网上你能搜到很多在线 Base64 的转换工具，有的叫 Base64 加密、解密，有的叫 Base64 编码、解码。可能这也是让大家搞混的原因之一吧，至少在我看来不是加密。只是将二进制数据转换成文本数据，便于传输。</p>
<blockquote>
<p>Base64 转换过程，参考下表：</p>
<p>表格来自维基百科</p>
</blockquote>
<figure data-type="image" tabindex="2"><img src="https://monster-image-backup.oss-cn-shanghai.aliyuncs.com/picgo/base64format.jpg" alt="Base64加密方法" loading="lazy"></figure>
<p>还有人说，使用 Base64 就不是为了安全，是因为它高效才用的。说这话的人，可能对 Base64 的编码过程不太了解，我来解释一下上面的图片的意思，Base64 是首先将待转换的数据在末尾以补 0 的方式将数据长度补全为 3 的倍数。然后以每 6 位作为一个字节，不足 6 位的最高位补 0，再将其对于到码表中，所以，使用 Base64 只会让数据长度变长，具体变长多少呢？1/3。既然使用 Base64 转换后的数据都变长了，怎么高效？</p>
<p>再多说一点点，仔细看，其实 Base64 不是 64 个字符，是 65 个，除了 a-z、A-Z、0-9 以及两个特殊字符外还有一个  <code>=</code> 作为结束标记。但是 <code>=</code> 不是一定会出现的。</p>
<h2 id="hash">Hash</h2>
<p>Hash 平时可能都有用过，但是不太熟悉，甚至，还可能觉得什么把 Hash 跟加密放在一起？是因为 Hash 跟 Base64 一样，也是容易被人混淆的。那么 Hash 到底是什么呢？Hash 在英语中有把……弄乱，切碎的意思。什么意思呢？就是把任意长度的数据映射为固定（有限）长度的数据。比如 <code>I'm a developer</code>  对应的 Hash 值如下：</p>
<ul>
<li>
<p>SHA1</p>
<blockquote>
<p>71c25c6e21f9a1571c8aab270d8a4dee3c2a07c1</p>
</blockquote>
</li>
<li>
<p>SHA256</p>
<blockquote>
<p>0f7f321e14c9dc026f95e7569dde90dcef988ff44d30ac2dc9e24168e05111b4</p>
</blockquote>
</li>
<li>
<p>MD5</p>
<blockquote>
<p>db32e7134744e20e174c9425e627dd10</p>
</blockquote>
</li>
</ul>
<p>可以看到，一个字符串有多个 Hash 值，这是什么情况呢？这是因为 Hash 有多种算法，SHA1、SHA256、MD5都是其中一种，还有其他的算法，比如 SHA224，同时不同的算法生成的 Hash 值的长度也不同。哎，那我同一个数据经过 Hash 之后得到的数据，变长了，或是变短了，是不是就是加密？</p>
<p>不好意思，还真不是，为什么呢？因为 Hash 的算法是不可逆的，说不可逆好像也不太合适，就是你只能使用 Hash 算法将 <code>I'm a developer</code> 变成上面几个数据中的一个，但是，你没办法通过 Hash 后的数据再转换到 <code>I'm a developer</code>。哇，听起来有点鸡肋啊，那他能干啥呀。不能加密算了，还产生那么一堆看起来没什么用的东西。别急啊。</p>
<p>因为一旦选定好 Hash 算法之后，Hash 值就是固定的了。所以，Hash 一般用来校验数据。比如，你在网上下载一个文件的时候，有些下载提供商会提供几种算法的 Hash 值，干啥呢。用来保证你下载的文件确定是没有被有心之人篡改后的。因为同样的数据对应的 Hash 值也是一致的，即使是略微的改动也会导致 Hash 值与之前的千差万别。比如<code>I'm a Developer</code> 我只是改了其中一个字母，使用 MD5 算法得到的 Hash 值为：</p>
<blockquote>
<p>1b77d24eb81c857f2f5505ca61eda70a</p>
</blockquote>
<p>你看，我只是把 <code>d</code> 改为 <code>D</code>，它与之前的 MD5 的值就完全不一样了。</p>
<p>那为什么还有人说，MD5 快被破解了？是这样的，因为 Hash 的被破解，不是真的说能将一个 Hash 后的字符串还原到源数据，而是说找到一种算法，通过这个算法能找到一个与源数据不同但经过 Hash 计算之后得出的 Hash值一致的情况。</p>
<p>连讲了两个都不是加密的东西，再不讲，加密，说不过去了。接下来开始对称加密、非对称加密。</p>
<h2 id="对称加密">对称加密</h2>
<p>对称加密的原理很简单就是加密与解密使用同一个密钥进行。即：使用加密算法与密钥对原数据进行加密，使用解密算法与密钥对密文进行解密。哎，等等，加密算法与解密算法？解释一下，解密算法是加密算法的反向运算。</p>
<figure data-type="image" tabindex="3"><img src="https://monster-image-backup.oss-cn-shanghai.aliyuncs.com/picgo/dvifjwmi.jpg" alt="对称加密原型图" loading="lazy"></figure>
<p>你看，由于加密与解密使用的是同一个密钥，所以安全性在一定程度上得不到保证。必须保证通信双方先拥有一套不被其他人知道的密钥。不过它也是有其他有点的，比如，性能好，计算速度快，不过这个也是在牺牲密钥长度的基础上做的，这么一看，好像优点不是那么明显……</p>
<p>常见的对称加密算法有：DES、3DES、AES、RC5、RC6。其中，DES 因为密钥长度太短已经逐渐被弃用。</p>
<h2 id="非对称加密">非对称加密</h2>
<p>刚才说了，对称加密是不能在不安全的网络中直接传输密钥的，那非对称加密呢？它是可以在网络上进行传输密钥的，因为它的密钥是两个。一个公钥，一个私钥。公钥用于在网络上进行传输，私钥留在自己手中用来解密。</p>
<figure data-type="image" tabindex="4"><img src="https://monster-image-backup.oss-cn-shanghai.aliyuncs.com/picgo/fzdvigjwmi.jpg" alt="非对称加密原型" loading="lazy"></figure>
<p>非对称加密使用进行公钥加密、私钥进行解密。使用公钥对数据进行加密得到密文，使用私钥对密文进行解密得到数据。私钥是能解开公钥加密的数据，公钥也能解开私钥加密的数据。</p>
<p>因为非对称加密中公钥与私钥是可以互相解开的，所以，非对称加密还可以用于数字签名，使用 <strong>私钥</strong> 对原数据的 Hash 值进行加密，然后，附加在原数据的后面，这样既保证了原数据是可读的，又可以在数据接收完成之后对数据的完整性加以验证。</p>
<figure data-type="image" tabindex="5"><img src="http://otow84eyx.bkt.clouddn.com/picGo/20180930122121.png" alt="" loading="lazy"></figure>
<p>非对称加密的优点与缺点也很清晰，优点就是能在网络上进行传输自己的密钥，就这一点来说，就已经比对称加密厉害了，因为如果对称加密把自己的密钥放在网络上 进行传输，很有可能被有心之人获取，然后做一些不可描述的事情。非对称加密就不会存在这个问题，因为它是有两个密钥的。这个是优点。缺点是什么呢？就是性能方面相对于对称加密差一点。</p>
<p>常见的算法有：RSA、ElGamal、背包算法、椭圆曲线加密算法。</p>
<h3 id="为什么经过非对称加密后的信息在网络传输中是安全的">为什么经过非对称加密后的信息在网络传输中是安全的</h3>
<p>这里引入一个场景。A、B 两人通信，C 作为坏人，截获、篡改 A、B 之间的通信内容。</p>
<p>先看看对称加密后的信息在网络传输中为什么是不安全的。</p>
<p>首先，因为对称加密需要双方共同有一套密钥，那么密钥是需要在网络上进行传输的，在这一步，就已经不安全了，因为，一旦 A、B 在网络上传输了密钥，C 一定能获取到，那么此后的所有经过加密的内容对于 C 来说，只是需要去把加密后的数据解开即可。</p>
<p><img src="http://otow84eyx.bkt.clouddn.com/20181006234543.PNG" alt="" loading="lazy">再来看看如果使用非对称加密该怎么做。</p>
<p>首先通信双方会先把自己的公钥发送给对方，然后使用对方的公钥对数据进行加密后传输。这个时候即使 C 在 A、B 交换公钥的过程中拿到公钥也是没用的，因为公钥是拿来加密的，而要解密就需要 A、B 的私钥了。所以这个时候 C 是不能进行截获的。这样就绝对安全了吗？并非如此，要知道，C 可是同时拥有 A、B 的公钥，那只有公钥能干什么呢？能伪造数据，C 虽然不能将 A、B 通信的内容进行获取、篡改，但是 C 能发送一个全新的数据，然后时候公钥进行加密呀。这样也是能达到欺骗对方的目的。所以这还不是最终的解决方案。</p>
<p><img src="http://otow84eyx.bkt.clouddn.com/20181006234551.PNG" alt="" loading="lazy">所以最终的解决方案是，使用自己的私钥对已经使用对方公钥的密文再加密一次。之前使用对方的公钥来进行加密，C 还能做到自己伪造一个假的数据，但是现在通信需要使用私钥再次加密了，C 连伪装都做不到了，为什么？因为 C 没有任何一方的私钥。</p>
<figure data-type="image" tabindex="6"><img src="http://otow84eyx.bkt.clouddn.com/20181006234559.PNG" alt="" loading="lazy"></figure>
<p>举个例子，C 使用 B 的公钥对伪装数据进行加密然后发送给 B，这时候 B 拿到数据会先用 A 的公钥来解开（因为在规定中，是先用 B 的公钥加密，然后再使用 A 的私钥进行加密，在解密的时候，就需要先使用 A 的公钥来解密，然后使用 B 的私钥再次解密），但这时候 B 会发现，经过 A 的公钥解密再次经过 B 的私钥解密后数据就完全没法看了。因为在加密的时候少了一个使用 A 的私钥进行加密的环节。</p>
<p>非对称加密有点绕，还是得自己多想想。到这里，已经非常像 HTTPS 了，但还不是，HTTPS 比这个非对称加密还稍微麻烦一点，敬请期待。</p>
<p>本文题图：Photo by <a href="https://unsplash.com/@markusspiske?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Markus Spiske</a> on <a href="https://unsplash.com/search/photos/encryption?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></p>

            </div>
          </article>
        </div>
    
        
          <div class="next-post">
            <div class="next">下一篇</div>
            <a href="https://cherrylover.github.io/post/kai-fa-zhong-ke-yi-bi-mian-de-wen-ti/">
              <h3 class="post-title">
                开发中可以避免的问题
              </h3>
            </a>
          </div>  
        

        
          
            <link rel="stylesheet" href="https://unpkg.com/gitalk/dist/gitalk.css">
<script src="https://unpkg.com/gitalk/dist/gitalk.min.js"></script>

<div id="gitalk-container"></div>

<script>

  var gitalk = new Gitalk({
    clientID: 'f5cc70d7d50fba65cf69',
    clientSecret: '1d018e38ce9cdd399682bdd76690decfef00a051',
    repo: 'CherryLover.github.io',
    owner: 'CherryLover',
    admin: ['CherryLover'],
    id: location.pathname,      // Ensure uniqueness and length less than 50
    distractionFreeMode: false  // Facebook-like distraction free mode
  })

  gitalk.render('gitalk-container')

</script>

          

          
        
    
        <div class="site-footer">
  Powered by <a href="https://github.com/getgridea/gridea" target="_blank">Gridea</a>
</div>

<script>
  hljs.initHighlightingOnLoad()
</script>

      </div>
    </div>
  </body>
</html>
